package com.white.loggerserver.core

import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.Handler
import android.os.IBinder
import android.os.Looper
import com.white.loggerserver.L
import java.io.IOException
import java.net.ServerSocket
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentMap
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.properties.Delegates

class LogServerService : Service() {

    private var server : LogServer by Delegates.notNull()
    private var listeners = Collections.synchronizedList(mutableListOf<UserListenCallback>())
    private var clients: ConcurrentMap<String, LogServerHandler> = ConcurrentHashMap()

    override fun onBind(intent: Intent): IBinder {
        return myBinder
    }

    private var myBinder = MyBinder()

    inner class MyBinder : Binder(){
        fun getService() : LogServerService{
            return this@LogServerService
        }
    }

    override fun onCreate() {
        super.onCreate()
        server = LogServer(3999, InnerCallbackImpl())
        server.start()
    }

    override fun onDestroy() {
        super.onDestroy()
        server.exit()
        L.e("service exit")
    }

    inner class LogServer(var port : Int, var callback : InnerListenCallback) : Thread(){

        private var server: ServerSocket? = null
        private var needExit = AtomicBoolean(false)

        override fun run() {

            try {
                server = ServerSocket(port)
            } catch (e: IOException) {
                needExit.set(true)
            }
            L.e("log service up")
            while (!needExit.get()) {
                try {
                    val localSocket = server!!.accept()
                    if (localSocket != null && !needExit.get()) {
                        val ip = localSocket.inetAddress.hostAddress
                        clients[ip] = LogServerHandler(ip, localSocket, ThreadPool.instance, callback)
                        clients[ip]?.start()
                    }
                } catch (e: IOException) {
                    e.printStackTrace()
                    closeServer()
                    break
                }
            }
        }

        private fun closeServer() {
            try {
                needExit.set(true)
                server?.close()
                server = null
            } catch (e: IOException) {
                e.printStackTrace()
            }
        }

        fun exit(){
            needExit.set(true)
            clients.values.forEach{
                it.close()
            }
            clients.clear()
            listeners.clear()
            closeServer()
        }
    }

    fun registerCallback(l : UserListenCallback){
        if(listeners.contains(l)){
            listeners.remove(l)
        }
        listeners.add(l)
    }

    fun unregisterCallback(l : UserListenCallback){
        listeners.remove(l)
    }

    inner class InnerCallbackImpl : InnerListenCallback{

        override fun onClientOnline(ip: String) {
            L.e("client size = ${clients.size}")
            listeners.forEach {
                it.onClientOnline(ip)
            }
        }

        override fun onClientOffline(ip: String) {
            clients.remove(ip)
            L.e("client size = ${clients.size}")
            listeners.forEach {
                it.onClientOffline(ip)
            }
        }

        override fun onReceiveMsg(ip: String, type: Int, timestamp: Long, msg: String) {
            listeners.forEach {
                it.onReceiveMsg(ip, type, timestamp, msg)
            }
        }
    }
}
